﻿using FFmpegDecodecVideo.AttributeUsageFolder;
using FFmpegDecodecVideo.FFmpegUlit;
using Microsoft.Graphics.Canvas;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using NAudio.Dsp;
using NAudio.Wave;
using System;
using System.Collections.Generic;
using System.Diagnostics;

using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace FFmpegDecodecVideo.Views
{
    [PageInfoAttibute("解码音频")]
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public unsafe sealed partial class FFmpegDecodecAudio : Page
    {
        Task PlayTask;

        DispatcherTimer timer = new DispatcherTimer();
        bool progressActivity = false;
        DecodecAudio audio = new DecodecAudio();

        //NAudio音频播放组件
        private WaveOut waveOut;
        private BufferedWaveProvider bufferedWaveProvider;
        WasapiLoopbackCapture capture = new WasapiLoopbackCapture();
        public FFmpegDecodecAudio()
        {
            this.InitializeComponent();
            Init();
            InitUi();
        }

        int frameCount = 0;
        void Init()
        {
            waveOut = new WaveOut();
            bufferedWaveProvider = new BufferedWaveProvider(new WaveFormat());
            waveOut.Init(bufferedWaveProvider);
            waveOut.Play();
            //播放
            play.Click += (s, e) =>
            {
                if (audio.State == MediaState.None)
                {
                    //初始化解码视频
                    audio.InitDecodecAudio(pathBox.Text);
                    DisplayVideoInfo();
                    audioBytes = new byte[audio.BitsPerSample];
                    tempAudioBytes = new byte[audio.BitsPerSample];
                }
                audio.Play();
                timer.Start();
            };
            //暂停
            pause.Click += (s, e) => audio.Pause();
            stop.Click += (s, e) => audio.Stop(); ;
            PlayTask = new Task(() =>
            {
                while (true)
                {
                    //播放中
                    if (audio.IsPlaying)
                    {
                        //获取下一帧视频
                        if (audio.TryReadNextFrame(out var frame))
                        {
                            var bytes = audio.FrameConvertBytes(&frame);
                            if (bytes == null)
                                continue;
                            if (bufferedWaveProvider.BufferLength <= bufferedWaveProvider.BufferedBytes + bytes.Length)
                            {
                                bufferedWaveProvider.ClearBuffer();
                            }
                            bufferedWaveProvider.AddSamples(bytes, 0, bytes.Length);//向缓存中添加音频样本

                            frameCount++;
                            if (frameCount == 5)
                            {
                                frameCount = 0;
                                audioBytes = bytes;
                                canvas.Invalidate();
                            }

                        }
                    }
                }
            })
            {

            };
            PlayTask.Start();
            audio.MediaCompleted += (s) =>
            {
                DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () =>
                {
                    timer.Stop();
                    progressActivity = false;
                    DisplayVideoInfo();
                });
            };
        }

        double canvasWidth;
        double canvasHeight;

        byte[] audioBytes;
        byte[] tempAudioBytes;
        double lastHeight = 0;
        void InitUi()
        {
            //画布绘制
            canvas.Draw += (s, e) =>
            {
                //if (points.Count == 0)
                //    return;
                //var py = points.Max(p => p.Y);

                //foreach (var item in points)
                //{
                //    var x = (item.X / points.Count) * canvasWidth;
                //    var y = (item.Y / py * 0.5 * canvasHeight);

                //    e.DrawingSession.DrawCircle(new Vector2((float)x, (float)y), 1, Colors.Red);
                //}

                if (audioBytes == null)
                    return;
                int number = 100;
                var w = canvasWidth / (audioBytes.Length / number);

                for (int i = 0; i < audioBytes.Length / number; i++)
                {
                    var a = audioBytes[i * number];
                    var b = tempAudioBytes[i * number];

                    var v = b + (a - b) * 0.5;
                    tempAudioBytes[i * number] = (byte)v;
                    var x = i * w;
                    var h = v / 255d * canvasHeight;
                    var y = canvasHeight - h;
                    var c = (byte)(255 - v);
                    var color = Color.FromArgb(255, c, c, c);

                    e.DrawingSession.FillRectangle(new Rect(x, y, w, h), color);
                }

                double sum = audioBytes.Sum(x => x);

                var height = sum / (double)(audioBytes.Length * 255) * canvasHeight;
              var  th = height + (lastHeight - height) * 0.5;
                lastHeight = height;
                e.DrawingSession.FillRectangle(new Rect(0, canvasHeight - th, 50, th), Colors.Red);

            };

            

            canvas.SizeChanged += (s, e) =>
            {
                canvasWidth = canvas.ActualWidth;
                canvasHeight = canvas.ActualHeight;
            };

            timer.Interval = TimeSpan.FromMilliseconds(300);
            //计时器更新进度条
            timer.Tick += (s, e) =>
            {
                if (!audio.IsPlaying)
                    return;
                position.Text = audio.Position.ToString();
                progressActivity = false;
                progress.Value = audio.Position.TotalSeconds;
                progressActivity = true;
            };
            //进度条更改
            progress.ValueChanged += (s, e) =>
            {
                if (!audio.IsPlaying)
                    return;
                if (progressActivity == true)
                {
                    audio.SeekProgress((int)e.NewValue);
                }
            };

            capture.DataAvailable += (s, e) =>
            {
                float[] allSamples = Enumerable.Range(0, e.BytesRecorded / 4).Select(i => BitConverter.ToSingle(e.Buffer, i * 4)).ToArray();


                int channelCount = capture.WaveFormat.Channels;
                float[][] channelSamples = Enumerable
    .Range(0, channelCount)
    .Select(channel => Enumerable
        .Range(0, allSamples.Length / channelCount)
        .Select(i => allSamples[channel + i * channelCount])
        .ToArray())
    .ToArray();

                float[] averageSamples = Enumerable
    .Range(0, allSamples.Length / channelCount)
    .Select(index => Enumerable
        .Range(0, channelCount)
        .Select(channel => channelSamples[channel][index])
        .Average())
    .ToArray();

                int log = (int)Math.Floor(Math.Log(averageSamples.Length, 2));
                float[] filledSamples = new float[(int)Math.Pow(2, log)];
                Array.Copy(averageSamples, filledSamples, Math.Min(averageSamples.Length, filledSamples.Length));   // 填充数据
                NAudio.Dsp.Complex[] complexSrc = filledSamples.Select((v, i) => new NAudio.Dsp.Complex() { X = v }).ToArray();
                FastFourierTransform.FFT(false, log, complexSrc);     // 进行傅里叶变换
                double[] result = complexSrc.Select(v => Math.Sqrt(v.X * v.X + v.Y * v.Y)).ToArray();    // 取得结果
                double[] reresult = result.Take(result.Length / 2).ToArray();                            // 取一半

                NAudio.Dsp.Complex[] halfData = complexSrc.Take(complexSrc.Length / 2).ToArray();    // 一半的数据
                double[] dftData = halfData.Select(v => Math.Sqrt(v.X * v.X + v.Y * v.Y)).ToArray(); // 取复数的模


                int count = 2500 / (capture.WaveFormat.SampleRate / filledSamples.Length);
                double[] finalData = dftData.Take(count).ToArray();

                points = finalData
    .Select((v, i) => new Point(i, canvasHeight - v))
    .ToList();
                canvas.Invalidate();
            };

            //capture.StartRecording();
        }


        List<Point> points = new List<Point>();

        /// <summary>
        /// 显示视频信息
        /// </summary>
        void DisplayVideoInfo()
        {
            dura.Text = audio.Duration.ToString();
            audioCodec.Text = audio.CodecName;
            audioBitrate.Text = audio.Bitrate.ToString();
            audioChannels.Text = audio.Channels.ToString();
            audioChannelsLayout.Text = audio.ChannelLyaout.ToString();
            audioSampleRate.Text = audio.SampleRate.ToString();
            audioBitsPerSample.Text = audio.BitsPerSample.ToString();
            position.Text = audio.Position.ToString();
            progress.Maximum = audio.Duration.TotalSeconds;
        }
    }
}
